"""
数据获取模块（增强版 V2.2.1）
增加智能交易日判断和数据获取逻辑
"""

import akshare as ak
import pandas as pd
from datetime import datetime, timedelta
import logging
import traceback
import time

from config import current_config as config
from utils.trading_calendar import TradingCalendar


class StockDataFetcherV2:
    """股票数据获取类（增强版，智能交易日判断）"""
    
    def __init__(self):
        self.stock_info = None
        self.logger = logging.getLogger(__name__)
        self.trading_calendar = TradingCalendar()
        self._check_trading_status()
    
    def _check_trading_status(self):
        """检查交易状态并记录日志"""
        if config.AUTO_DETECT_TRADING_DAY:
            status = self.trading_calendar.get_trading_status()
            logging.info("=" * 60)
            logging.info("交易日历状态检测")
            logging.info("=" * 60)
            for key, value in status.items():
                logging.info(f"{key}: {value}")
            logging.info("=" * 60)
            
            # 判断是否应该使用实时数据
            use_realtime, target_date = self.trading_calendar.should_use_realtime_data()
            
            if config.FORCE_USE_DATE:
                logging.info(f"⚙️ 配置强制使用日期: {config.FORCE_USE_DATE}")
            elif not use_realtime:
                logging.info(f"⚠️ 今日非交易时间或休市，将使用 {target_date} 的数据")
            else:
                logging.info(f"✅ 今日交易中，使用实时数据")
    
    def get_stock_code(self, input_str):
        """
        将股票名称或代码转换为标准代码
        """
        try:
            logging.info(f"开始查找股票: {input_str}")
            
            # 如果是6位数字，直接返回
            if input_str.isdigit() and len(input_str) == 6:
                logging.info(f"输入为6位数字代码: {input_str}")
                return input_str
            
            # 搜索股票代码
            logging.info("正在获取股票列表...")
            stock_info = ak.stock_info_a_code_name()
            logging.info(f"股票列表获取成功，共 {len(stock_info)} 只股票")
            
            result = stock_info[stock_info['name'].str.contains(input_str, na=False)]
            
            if len(result) > 0:
                code = result.iloc[0]['code']
                name = result.iloc[0]['name']
                logging.info(f"找到股票: {name} ({code})")
                return code
            else:
                logging.warning(f"未找到股票: {input_str}")
                return None
                
        except Exception as e:
            logging.error(f"获取股票代码失败: {type(e).__name__}: {str(e)}")
            logging.error(f"详细错误:\n{traceback.format_exc()}")
            return None
    
    def get_realtime_data(self, stock_code, retry=3):
        """
        获取实时行情数据（智能版）
        根据配置和交易状态智能选择数据源
        """
        # 检查是否强制使用指定日期
        if config.FORCE_USE_DATE:
            logging.info(f"⚙️ 配置强制使用日期: {config.FORCE_USE_DATE}")
            return self._get_historical_as_realtime(stock_code, config.FORCE_USE_DATE)
        
        # 自动检测交易日
        if config.AUTO_DETECT_TRADING_DAY and config.USE_LAST_TRADING_DAY_ON_HOLIDAY:
            use_realtime, target_date = self.trading_calendar.should_use_realtime_data()
            
            if not use_realtime:
                logging.info(f"⚠️ 今日非交易时间或休市，使用 {target_date} 的数据")
                date_str = target_date.strftime('%Y-%m-%d')
                return self._get_historical_as_realtime(stock_code, date_str)
        
        # 正常获取实时数据
        for attempt in range(retry):
            try:
                if attempt > 0:
                    wait_time = attempt * 2
                    logging.info(f"第{attempt + 1}次重试，等待{wait_time}秒...")
                    time.sleep(wait_time)
                
                logging.info(f"开始获取实时行情: {stock_code} (尝试 {attempt + 1}/{retry})")
                
                # 使用akshare获取实时行情
                stock_zh_a_spot = ak.stock_zh_a_spot_em()
                
                if stock_zh_a_spot is None or stock_zh_a_spot.empty:
                    logging.warning(f"实时数据为空")
                    continue
                
                # 查找对应股票
                stock_data = stock_zh_a_spot[stock_zh_a_spot['代码'] == stock_code]
                
                if stock_data.empty:
                    logging.error(f"未找到股票代码: {stock_code}")
                    # 如果实时数据获取失败且配置允许，尝试使用历史数据
                    if config.USE_LAST_TRADING_DAY_ON_HOLIDAY:
                        logging.info("⚠️ 实时数据获取失败，尝试使用最近交易日数据")
                        last_trading = self.trading_calendar.get_last_trading_day()
                        date_str = last_trading.strftime('%Y-%m-%d')
                        return self._get_historical_as_realtime(stock_code, date_str)
                    return None
                
                data = stock_data.iloc[0]
                
                realtime_data = {
                    '股票代码': stock_code,
                    '股票名称': data['名称'],
                    '最新价': float(data['最新价']),
                    '涨跌幅': float(data['涨跌幅']),
                    '涨跌额': float(data['涨跌额']),
                    '成交量': float(data['成交量']),
                    '成交额': float(data['成交额']),
                    '换手率': float(data['换手率']),
                    '量比': float(data['量比']),
                    '开盘价': float(data['今开']),
                    '最高价': float(data['最高']),
                    '最低价': float(data['最低']),
                    '昨收': float(data['昨收']),
                    '市盈率': float(data['市盈率-动态']) if '市盈率-动态' in data else None,
                    '市净率': float(data['市净率']) if '市净率' in data else None,
                    '总市值': float(data['总市值']),
                    '流通市值': float(data['流通市值']),
                    '数据来源': '实时数据',
                    '数据时间': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                }
                
                logging.info(f"✅ 实时数据获取成功: {realtime_data['股票名称']} 最新价: {realtime_data['最新价']}")
                return realtime_data
                
            except Exception as e:
                logging.warning(f"第{attempt + 1}次获取实时数据失败: {type(e).__name__}: {str(e)}")
                if attempt == retry - 1:
                    logging.error(f"获取实时数据失败（已重试{retry}次）")
                    logging.error(f"详细错误:\n{traceback.format_exc()}")
                    
                    # 如果所有重试都失败且配置允许，使用历史数据
                    if config.USE_LAST_TRADING_DAY_ON_HOLIDAY:
                        logging.info("⚠️ 实时数据获取失败，尝试使用最近交易日数据")
                        last_trading = self.trading_calendar.get_last_trading_day()
                        date_str = last_trading.strftime('%Y-%m-%d')
                        return self._get_historical_as_realtime(stock_code, date_str)
                    return None
        
        return None
    
    def _get_historical_as_realtime(self, stock_code, date_str):
        """
        使用历史数据模拟实时数据
        用于休市或指定日期的数据获取
        """
        try:
            logging.info(f"📅 尝试获取 {date_str} 的历史数据作为实时数据")
            
            # 获取指定日期前后几天的数据，确保能获取到
            target_date = datetime.strptime(date_str, '%Y-%m-%d').date()
            end_date = target_date + timedelta(days=3)
            start_date = target_date - timedelta(days=10)
            
            df = ak.stock_zh_a_hist(
                symbol=stock_code,
                period="daily",
                start_date=start_date.strftime('%Y%m%d'),
                end_date=end_date.strftime('%Y%m%d'),
                adjust="qfq"
            )
            
            if df is None or df.empty:
                logging.error(f"未能获取 {date_str} 的历史数据")
                return None
            
            # 标准化列名
            if len(df.columns) == 12:
                df.columns = ['日期', '股票代码', '开盘', '收盘', '最高', '最低', '成交量', '成交额',
                             '振幅', '涨跌幅', '涨跌额', '换手率']
                df = df.drop('股票代码', axis=1)
            elif len(df.columns) == 11:
                df.columns = ['日期', '开盘', '收盘', '最高', '最低', '成交量', '成交额',
                             '振幅', '涨跌幅', '涨跌额', '换手率']
            
            df['日期'] = pd.to_datetime(df['日期'])
            
            # 找到最接近目标日期的数据
            df['date_only'] = df['日期'].dt.date
            closest_data = df[df['date_only'] <= target_date].tail(1)
            
            if closest_data.empty:
                closest_data = df.head(1)
            
            data = closest_data.iloc[0]
            actual_date = data['日期'].strftime('%Y-%m-%d')
            
            # 获取股票名称
            try:
                all_stocks = ak.stock_info_a_code_name()
                stock_row = all_stocks[all_stocks['code'] == stock_code]
                stock_name = stock_row.iloc[0]['name'] if len(stock_row) > 0 else stock_code
            except:
                stock_name = f"股票{stock_code}"
            
            # 估算昨收
            prev_close = data['开盘'] / (1 + data['涨跌幅'] / 100) if data['涨跌幅'] != 0 else data['开盘']
            
            realtime_data = {
                '股票代码': stock_code,
                '股票名称': stock_name,
                '最新价': float(data['收盘']),
                '涨跌幅': float(data['涨跌幅']),
                '涨跌额': float(data['涨跌额']),
                '成交量': float(data['成交量']),
                '成交额': float(data['成交额']),
                '换手率': float(data['换手率']),
                '量比': 1.0,  # 历史数据无法获取量比，设为1
                '开盘价': float(data['开盘']),
                '最高价': float(data['最高']),
                '最低价': float(data['最低']),
                '昨收': float(prev_close),
                '市盈率': None,  # 历史数据无法获取
                '市净率': None,
                '总市值': None,
                '流通市值': None,
                '数据来源': f'历史数据（{actual_date}）',
                '数据时间': actual_date,
            }
            
            logging.info(f"✅ 成功使用 {actual_date} 的历史数据: {stock_name} 收盘价: {realtime_data['最新价']}")
            return realtime_data
            
        except Exception as e:
            logging.error(f"获取历史数据作为实时数据失败: {type(e).__name__}: {str(e)}")
            logging.error(f"详细错误:\n{traceback.format_exc()}")
            return None
    
    def get_historical_data(self, stock_code, period='daily', adjust='qfq', days=250):
        """
        获取历史数据
        """
        try:
            end_date = datetime.now()
            start_date = end_date - timedelta(days=days)
            
            logging.info(f"开始获取历史数据: {stock_code}")
            logging.info(f"周期: {period}, 复权: {adjust}, 天数: {days}")
            logging.info(f"日期范围: {start_date.strftime('%Y%m%d')} 至 {end_date.strftime('%Y%m%d')}")
            
            df = ak.stock_zh_a_hist(
                symbol=stock_code,
                period=period,
                start_date=start_date.strftime('%Y%m%d'),
                end_date=end_date.strftime('%Y%m%d'),
                adjust=adjust
            )
            
            if df is not None and len(df) > 0:
                logging.info(f"历史数据获取成功: 共 {len(df)} 条记录")
                logging.info(f"数据列: {df.columns.tolist()}")
                
                # 处理列数不同的情况
                if len(df.columns) == 12:
                    logging.info("检测到12列数据格式（包含股票代码列）")
                    df.columns = ['日期', '股票代码', '开盘', '收盘', '最高', '最低', '成交量', '成交额',
                                 '振幅', '涨跌幅', '涨跌额', '换手率']
                    df = df.drop('股票代码', axis=1)
                elif len(df.columns) == 11:
                    logging.info("检测到11列数据格式")
                    df.columns = ['日期', '开盘', '收盘', '最高', '最低', '成交量', '成交额',
                                 '振幅', '涨跌幅', '涨跌额', '换手率']
                else:
                    logging.warning(f"未知的列数格式: {len(df.columns)}列")
                    logging.warning(f"实际列名: {df.columns.tolist()}")
                
                df['日期'] = pd.to_datetime(df['日期'])
                logging.info(f"数据日期范围: {df['日期'].min()} 至 {df['日期'].max()}")
                logging.info(f"最终列名: {df.columns.tolist()}")
                return df
            else:
                logging.warning("历史数据为空")
                return None
                
        except Exception as e:
            logging.error(f"获取历史数据失败: {type(e).__name__}: {str(e)}")
            logging.error(f"股票代码: {stock_code}, period: {period}, days: {days}")
            logging.error(f"详细错误:\n{traceback.format_exc()}")
            return None
    
    def get_minute_data(self, stock_code, period='1'):
        """
        获取分钟数据
        """
        try:
            logging.info(f"开始获取分钟数据: {stock_code}, 周期: {period}分钟")
            
            df = ak.stock_zh_a_hist_min_em(
                symbol=stock_code,
                period=period,
                adjust='qfq'
            )
            
            if df is not None and len(df) > 0:
                logging.info(f"分钟数据获取成功: 共 {len(df)} 条记录")
                return df
            else:
                logging.warning("分钟数据为空")
                return None
                
        except Exception as e:
            logging.error(f"获取分钟数据失败: {type(e).__name__}: {str(e)}")
            logging.error(f"详细错误:\n{traceback.format_exc()}")
            return None


# 向后兼容的别名
StockDataFetcher = StockDataFetcherV2

